package pl.edu.agh.inpema.core.environment;

import java.io.IOException;
import java.util.Date;
import java.util.Set;

import javax.jms.JMSException;

import org.apache.log4j.Logger;
import org.xml.sax.SAXException;

import pl.edu.agh.inpema.core.components.AnalyzerUtil;
import pl.edu.agh.inpema.core.components.ReadOnlyReceiver;
import pl.edu.agh.inpema.core.components.ReceiverUtil;
import pl.edu.agh.inpema.core.configuration.Configuration;
import pl.edu.agh.inpema.core.configuration.ConfigurationException;
import pl.edu.agh.inpema.core.dataBase.DataBase;
import pl.edu.agh.inpema.core.dataBase.DataBaseFactory;
import pl.edu.agh.inpema.core.model.Analyzer;
import pl.edu.agh.inpema.core.model.Receiver;
import pl.edu.agh.inpema.core.queue.Queue;
import pl.edu.agh.inpema.core.queue.impl.QueueImpl;

public class Environment {
	
	private Queue queue;
	private DataBase dataBase;
	private Set<Receiver> receivers;
	private Set<Analyzer> analyzers;
	
	Logger logger = Logger.getLogger(Environment.class);
	
	private EnvironmentInfo currentEnvironmentInfo;	
	
	public Environment(EnvironmentInfo currentEnvironmentInfo) {
		this.currentEnvironmentInfo = currentEnvironmentInfo;
	}
	
	public void configure() {
		Configuration configuration = new Configuration();
		try {
			configuration.readStringXMLConfiguration(this.currentEnvironmentInfo.getXmlConfiguration());
			receivers = configuration.getReceivers();
			analyzers = configuration.getAnalyzers();
		} catch (IOException e) {
			e.printStackTrace();
			System.exit(1);
		} catch (SAXException e) {
			e.printStackTrace();
			System.exit(1);
		} catch (ConfigurationException e) {
			e.printStackTrace();
			System.exit(1);
		}			
		logger.info("system configuration done");
	}
	
	public Set<Analyzer> getAnalyzers() {
		return this.analyzers;
	}
	
	public Set<Receiver> getReceivers() {
		return this.receivers;
	}
	
	public void startEnvironment() {
		Date now = new Date(System.currentTimeMillis());
		this.currentEnvironmentInfo.setStartTime(now);
		this.dataBase.updateEnvironment(this.currentEnvironmentInfo);
		for (Analyzer analyzer : analyzers) {
			analyzer.startAnalyzer();
		}
		for (Receiver receiver : receivers) {
			receiver.startGathering();
		}
	}
	
	public void stopEnvironment(boolean isError) {
		boolean isSuccess = ! isError;
		for (Receiver receiver : receivers) {
			if (receiver.stopGathering() == true)
				isSuccess = false;
		}
		for (Analyzer analyzer : analyzers) {
			if(analyzer.stopAnalyzer() == true)
				isSuccess = false;
		}
		Date now = new Date(System.currentTimeMillis());
		this.currentEnvironmentInfo.setEndTime(now);
		this.currentEnvironmentInfo.setSuccess(isSuccess);
		this.dataBase.updateEnvironment(this.currentEnvironmentInfo);
	}
	
	public boolean isReceiversRunning() {
		boolean receiversRunning = false;
		for (Receiver receiver : receivers) {
			if (receiver.isGatheringRunning()) {
				receiversRunning = true;
				break;
			}
		}
		return receiversRunning;
	}
	
	public void startConnection() throws JMSException {
		this.queue = new QueueImpl();
		this.queue.startConnection();
		
		this.dataBase = DataBaseFactory.getDataBaseForEnvironment(analyzers);
		
		this.currentEnvironmentInfo.setId(dataBase.generateNewEnvironmentId(this.currentEnvironmentInfo));
		this.dataBase.setCurrentEnvironmentId(this.currentEnvironmentInfo.getId());
		
		for (Analyzer analyzer : analyzers) {
			AnalyzerUtil analyzerUtil = analyzer.getAnalyzerUtil();
			analyzerUtil.setDataBase(dataBase);
			analyzerUtil.setQueue(queue);
			dataBase.addAnalyzer(analyzerUtil.getAnalyzerName());
			queue.createQueue(analyzerUtil.getAnalyzerName());
		}

		for (Receiver receiver : receivers) {
			if (receiver.getClass() == ReadOnlyReceiver.class) {
				ReadOnlyReceiver readOnlyReceiver = (ReadOnlyReceiver) receiver;
				readOnlyReceiver.setDataBase(dataBase);
				readOnlyReceiver.setQueue(queue);
			} else {
				ReceiverUtil receiverUtil = receiver.getReceiverUtil();
				receiverUtil.setDataBase(dataBase);
				receiverUtil.setQueue(queue);
				dataBase.addReceiver(receiverUtil.getReceiverName());
			}
		}
	}
	
	public void closeConnection() {
		this.queue.closeConnection();
		this.dataBase.closeConnection();
	}
}
